package cn.gemframe.oauth2.security.config;

import cn.gemframe.config.security.GemAuthProperties;
import cn.gemframe.config.security.GemTokenProperties;
import cn.gemframe.oauth2.bean.RequestPath;
import cn.gemframe.oauth2.security.exception.GemOAuth2Exception;
import cn.gemframe.oauth2.security.filter.GemAccessTokenValidateFilter;
import cn.gemframe.oauth2.security.filter.GemPermissionsValidateFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;

import java.util.UUID;

/***
 * 资源服务器配置
 */
@Slf4j
@Configuration
@EnableResourceServer
public class GemResourceConfig extends ResourceServerConfigurerAdapter {


	@Autowired
	private Environment env;

	//OAuth2
	@Autowired
	private GemOAuth2Exception oauth2Exception;
	@Autowired
	private GemAuthProperties gemAuthProperties;
	@Autowired
	private GemTokenProperties gemTokenProperties;

	//Redis
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;
    @Autowired
    private ValueOperations<String, Object> valueOperations;

	@Override
	public void configure(HttpSecurity http) throws Exception {

		boolean isTokenOpenAuth = gemTokenProperties.isOpenAuth();
		log.error("============token验证开关=================={}",isTokenOpenAuth);
		//权限过滤器
		GemPermissionsValidateFilter permissionsValidateFilter = new GemPermissionsValidateFilter();
		permissionsValidateFilter.setGemAuthProperties(gemAuthProperties);

		//token过滤器
		GemAccessTokenValidateFilter tokenValidateFilter = new GemAccessTokenValidateFilter();
		tokenValidateFilter.setValueOperations(valueOperations);
		tokenValidateFilter.setRedisTemplate(redisTemplate);
		tokenValidateFilter.setTokenStore(redisTokenStore());

		// 在登陆之前添加用户登录限制的过滤器
		if(isTokenOpenAuth){
			http.addFilterBefore(tokenValidateFilter, AbstractPreAuthenticatedProcessingFilter.class);
		}
		// 权限拦截
		http.addFilterBefore(permissionsValidateFilter, UsernamePasswordAuthenticationFilter.class);

		// 设置请求拦截
		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry
				authorizeRequests = http.authorizeRequests();
		// 不需要拦截的请求
		authorizeRequests.antMatchers(RequestPath.Access.SWAGGER_UI,
				RequestPath.Access.SWAGGER_RES,
				RequestPath.Access.SWAGGER_RES_X,
				RequestPath.Access.APIDOCS).permitAll();
		String noRelease = UUID.randomUUID().toString();
		log.error("noRelease========================={}",noRelease);
		if (noRelease != null && !noRelease.equalsIgnoreCase("null") && noRelease.length() > 0) {
			String[] split = noRelease.split(",");
			for (String noReleaseUrl : split) {
				if (noReleaseUrl != null && !noReleaseUrl.equalsIgnoreCase("null") && noReleaseUrl.length() > 0) {
					authorizeRequests.antMatchers(noReleaseUrl).permitAll();
				}
			}
		}
		authorizeRequests.antMatchers(HttpMethod.OPTIONS).permitAll();
		if(isTokenOpenAuth){
			// 设置拦截所有的请求
			authorizeRequests.anyRequest().authenticated();
		}
		// 进制跨域请求
		authorizeRequests.and().csrf().disable();
	}

	@Override
	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
		resources.tokenStore(redisTokenStore());
	}


	@Bean
	public TokenStore redisTokenStore() {
		return new RedisTokenStore(redisConnectionFactory);
	}

	public OAuth2AuthenticationProcessingFilter authenticationProcessingFilter() {
		OAuth2AuthenticationProcessingFilter oauth2AuthenticationProcessingFilter = new OAuth2AuthenticationProcessingFilter();
		OAuth2AuthenticationEntryPoint oAuth2AuthenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
		oAuth2AuthenticationEntryPoint.setExceptionTranslator(webResponseExceptionTranslator());
		oauth2AuthenticationProcessingFilter.setAuthenticationEntryPoint(oAuth2AuthenticationEntryPoint);
		OAuth2AuthenticationManager oauth2AuthenticationManager = new OAuth2AuthenticationManager();
		DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
		defaultTokenServices.setTokenStore(redisTokenStore());
		oauth2AuthenticationManager.setTokenServices(defaultTokenServices);
		oauth2AuthenticationProcessingFilter.setAuthenticationManager(oauth2AuthenticationManager);
		return oauth2AuthenticationProcessingFilter;
	}

	@Bean
	public WebResponseExceptionTranslator webResponseExceptionTranslator() {
		return oauth2Exception;
	}

}
